#include <ESP8266WebServer.h>
#include "config.h"

const char *AutoConfigHTML = u8R"esp8266_html(<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF8">
    <title>ESP8266自动配置</title>
</head>

<body style="font-size: 30px">

    <style>
        .inputText {
            height: 38px;
            font-size: 30px;
            line-height: 30px;
            padding-left: 15px;
            border-radius: 10px;
            background-color: #dff1f7;
            border: 2;
        }

        .inputText:focus {
            outline: none;
            background-color: #d6e4eb;
        }

        .buttonText {
            height: 38px;
            font-size: 30px;
            line-height: 30px;
            padding-left: 15px;
            border-radius: 10px;
            background-color: #FE5E08;
            border: none;
        }

        .buttonText:focus {
            outline: none;
            background-color: #FE5E08;
        }

        .buttonText:disabled {
            background-color: #c9c7c6;
        }
    </style>

    <center>
        <form>
            <table>
                <tr>
                    <td>Wifi SSID:</td>
                    <td><input type="text" class="inputText" id="SSID" placeholder="WIFI SSID"></td>
                </tr>
                <tr>
                    <td>Wifi 密码:</td>
                    <td><input type="text" class="inputText" id="PSW" placeholder="WIFI PASSWORD"></td>
                </tr>
                <tr>
                    <td>巴法云私钥:</td>
                    <td><input type="text" class="inputText" id="KEY" placeholder="USER KEY"></td>
                </tr>
                <tr>
                    <td>主题名:</td>
                    <td><input type="text" class="inputText" id="TOPIC" placeholder="TOPIC"></td>
                </tr>
            </table>
            <input id="btnsendconfig" type="button" class="buttonText" value="保存设置" onclick="config()">
        </form>
        <label id="recvtxt"></label>
    </center>
    <script language="javascript">
        function isNotEmptyStr(s) {
            if (typeof s == 'string' && s.length > 0) {
                return true
            }
            return false
        }
        function config() {
            var ssid = SSID.value;
            var psw = PSW.value;
            var key = KEY.value;
            var topic = TOPIC.value;

            if (!isNotEmptyStr(ssid)) {
                alert("请输入有效的SSID");
                return;
            }
            if (!isNotEmptyStr(psw)) {
                alert("请输入有效的Wifi密码");
                return;
            }
            if (!isNotEmptyStr(key)||key.length!=32) {
                alert("请输入有效的私钥");
                return;
            }
            if (!isNotEmptyStr(topic)) {
                alert("请输入有效的主题名");
                return;
            }
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4) {
                    document.getElementById("recvtxt").innerText = xmlhttp.responseText;
                    if (xmlhttp.status == 200) {
                        alert("设置成功");
                        window.location.href = "about:blank";
                        window.close();
                    }
                    else {
                        alert("设置失败");
                        document.getElementById("btnsendconfig").disabled = false;
                    }
                }
            }
            xmlhttp.ontimeout = function () {
                window.location.href = "about:blank";
                window.close();
            }
            xmlhttp.open("GET", "/AutoConfig?ssid=" + ssid + "&psw=" + psw+"&key="+key+"&topic="+topic, true);
            xmlhttp.timeout = 5000;
            xmlhttp.send();
            document.getElementById("btnsendconfig").disabled = true;
        }
    </script>
</body>

</html>)esp8266_html";

class CAutoConnect
{
    CConfigMgr &m_configMgr = CConfigMgr::getSingleton();

    ESP8266WebServer m_autoConfigWebServer;

    bool m_bRunFirst = true;

    void TryConnect(const char *SSID, const char *PSW)
    {
        int tryCount = 0;
        WiFi.begin(SSID, PSW);
        // WiFi.waitForConnectResult();
        while ((tryCount < MAX_TRY_COUNT) && (WiFi.status() != WL_CONNECTED))
        {
            delay(1000);
            tryCount++;
        }
    }

    void HandleHtmlRoot()
    {
        m_autoConfigWebServer.send(200, "text/html", AutoConfigHTML);
    }

    void HandleHtmlAutoConfig()
    {
        String ssid, psw, key, topic;
        ssid = m_autoConfigWebServer.arg("ssid");
        psw = m_autoConfigWebServer.arg("psw");
        key = m_autoConfigWebServer.arg("key");
        topic = m_autoConfigWebServer.arg("topic");

        Serial.println("HTML设置：ssid--" + ssid + "--|--psw--" + psw + "--|--key--" + key + "--|--topic--" + topic);

        Serial.println("尝试连接路由器，SSID: " + ssid + "密码: " + psw);

        TryConnect(ssid.c_str(), psw.c_str());

        if (WiFi.status() == WL_CONNECTED)
        {
            m_autoConfigWebServer.send(200, "text/html", "connect sucessed");
            Serial.println("------------连接路由器成功------------");
            m_configMgr.SetSSID(ssid.c_str());
            m_configMgr.SetPSW(psw.c_str());
            m_configMgr.SetKEY(key.c_str());
            m_configMgr.SetTOPIC(topic.c_str());
            // 保存一下，这玩意儿一般就是拔电。要自动析构保存怕是比较难
            m_configMgr.SaveConfig();
        }
        else
        {
            // 只保存key
            m_configMgr.SetKEY(key.c_str());
            m_configMgr.SetTOPIC(topic.c_str());
            m_configMgr.SaveConfig();

            m_autoConfigWebServer.send(500, "text/html", "connect error");
            Serial.println("------------连接路由器失败------------");
        }
    }

    void WifiDisConnected(const WiFiEventStationModeDisconnected &e)
    {
        // 尝试重新配网
        Serial.println("尝试重新配网");
        int trycount = 0;
        while (trycount < 10)
        {
            delay(1000);
            if (WiFi.status() == WL_CONNECTED)
            {
                Serial.println("----配网成功----");
                break;
            }
        }
        // 如果还没连接成功就启动重新配网
        if (WiFi.status() != WL_CONNECTED)
        {
            m_bRunFirst = true;
            AutoConnect();
        }
    }

    void HtmlConfigInit()
    {
        WiFi.mode(WIFI_AP_STA); // 双模式
        WiFi.setAutoReconnect(true);
        WiFi.onStationModeDisconnected(std::bind(&CAutoConnect::WifiDisConnected, this, std::placeholders::_1));

        IPAddress ip, gateway, subnet;
        ip.fromString("192.168.1.1");
        gateway.fromString("192.168.1.1");
        subnet.fromString("255.255.255.0");
        WiFi.softAPConfig(ip, gateway, subnet);

        WiFi.softAP(AUTOCFGSSID, AUTOCFGPSW);

        m_autoConfigWebServer.on("/", std::bind(&CAutoConnect::HandleHtmlRoot, this));
        m_autoConfigWebServer.on("/AutoConfig", HTTP_GET, std::bind(&CAutoConnect::HandleHtmlAutoConfig, this));
        m_autoConfigWebServer.begin(80);
    }

public:
    CAutoConnect()
    {
        HtmlConfigInit();
    }

    ~CAutoConnect() {}

    void AutoConnect()
    {
        if (m_bRunFirst)
        {
            HtmlConfig(true);
            m_bRunFirst = false;
        }

        // wifi已经连接直接退出
        if (WiFi.status() == WL_CONNECTED)
            return;

        if (m_configMgr.IsWifiInfoValid())
        {
            TryConnect(m_configMgr.SSID().c_str(), m_configMgr.PSW().c_str());
            if (WiFi.status() == WL_CONNECTED)
                return;
        }
        HtmlConfig();
    }

    void HtmlConfig(bool useTimeout = false)
    {

        unsigned long start = millis();

        Serial.println("进入HTML配网模式");
        while (true)
        {
            m_autoConfigWebServer.handleClient();
            if (WiFi.status() == WL_CONNECTED)
            {
                Serial.println("----配网成功----");
                m_autoConfigWebServer.close();
                break;
            }
            // 120秒还没有连接则退出
            if (useTimeout && (millis() - start >= 120 * 1000))
            {
                break;
            }
        }
    }
};
